function Player(user) {
    this.uid = user._id;
    this.user = clone(user);
    /*
    this.user = {
        _id: uid,
        info: {
            un: '',         // 名称
            headpic: '',    // 头像
        }

        status: {
            level: 0,
            vip: 0,
        }



        smashland: {            //九州英雄榜
            round: 0,               //轮数
            score: 0,               //积分
            rankScore: 0,           //排名时的积分
            rank: 0,                //排名
            award: 0,               //领奖标志
        }

        role: {}                //武将信息
        pet: {}                 //神兽信息
        roleAttrs: {}           //武将属性

        champsbattle: {         //王者战场
            round: 0,               //轮数
            step: 0,                //阶段

            attrs: {                //武将信息
                $rid: {                 //武将Id
                    init_health: 0,         //初始血量
                    health: 0,              //当前血量
                }
            },

            teamSaved: false,       //是否已保存了阵型
            teams: {                //布阵列表
                $id: {                  //阵型Id(1/2/3 前军/中军/后军)
                    team: {                 //阵型配置
                        $pos:0,                 //pos:武将Id 
                    },
                    
					freeRelive: 0,          //已免费复活次数
           			cashRelive: 0,          //已付费复活次数
                }
            },

            score: 0,               //最终积分
        }
    }
    */

    this.loaded = false;
    this.dirty = {};
}

Player.prototype = {

    //标记需要保存的字段，仅支持一层
    markDirty: function(item) {
        this.dirty[item] = 0;
    },

    save: function(force, callback) {
        if (force && this.loaded) {
            gDBUser.save(this.user, function(err, result){
                callback && callback(err);
            });
            return;
        }
        
        var sets = {};
        var setCount = 0;

        for (var item in this.dirty) {
            var obj = this.user;
            var args = item.split(".");
            var ok = true;
            for (var i = 0, max = args.length; i < max; ++i) {
                if( typeof(obj) != 'object' ) {
                    ok = false;
                    break;
                }

                obj = obj[args[i]];
            }

            if (ok && obj != undefined && obj != null) {
                sets[item] = obj;
                setCount++;
            } else {
                ERROR(util.format('%d save invalid %s', this.uid, item));
            }
        }
        this.dirty = {};

        if (setCount < 1) {
            callback && callback();
            return;
        }

        gDBUser.update({_id : this.uid}, {'$set':sets}, function(err, result) {
            callback && callback(err);
        });
    },

    getFightForce: function() {
        var roles = this.user.role;
        if (!roles) {
            return 0;
        }

        var fightForce = 0;
        for (var rid in roles) {
            fightForce += roles[rid].fight_force;
        }
        return fightForce;
    },

    getSmashLand: function() {
        var round = GlobalSmashLandRank.getRound();
        var smashland = this.user.smashland;
        if (!smashland || (smashland.round != round)) {
            this.user.smashland = {
                round: round,           //轮数
                score: 0,               //积分
                rankScore: 0,           //排名时的积分
                rank: 0,                //排名
                award: 0,               //领奖标志
            }
            this.markDirty('smashland');
        }
        return this.user.smashland;
    },

    getChampsBattle: function() {
        var round = gChampsBattle.getRound();
        var step = gChampsBattle.getSchedule().step;
        var champsbattle = this.user.champsbattle;

        if (!champsbattle || round != champsbattle.round) {
            this.user.champsbattle = {
            	round: round,
                step: step,
            	attrs: {},
            	teamSaved: false,
            	teams: {},
                score:0,
            }
            champsbattle = this.user.champsbattle;
            
         	this.markDirty('champsbattle.round');
         	this.markDirty('champsbattle.step');
        	this.markDirty('champsbattle.attrs');
        	this.markDirty('champsbattle.teamSaved');             
        	this.markDirty('champsbattle.score');             
            for (var id = 1; id <= gConfGlobal.ChampsBattleTeamCount; ++id) {
            	var team = {
            		team:{},
            		freeRelive: 0,
            		cashRelive: 0,
            	}
            	
            	champsbattle.teams[id] = team;
                this.markDirty(util.format('champsbattle.teams.%d.team', id));
                this.markDirty(util.format('champsbattle.teams.%d.freeRelive', id));
                this.markDirty(util.format('champsbattle.teams.%d.cashRelive', id));
            }
        } else if (step != champsbattle.step) {
    	    var teams = champsbattle.teams;
    	    for (var id in teams) {
    	    	var team = teams[id];
    	    	team.freeRelive = 0;
    	    	team.cashRelive = 0;
    	    	this.markDirty(util.format('champsbattle.teams.%d.freeRelive', id));
    	    	this.markDirty(util.format('champsbattle.teams.%d.cashRelive', id));
    	    }

            objectForEach(champsbattle.attrs, function(rid, attr) {
                attr.health = attr.init_health;
            });
            
            champsbattle.step = step;
            champsbattle.teamSaved = false;
            champsbattle.score = 0;
            this.markDirty('champsbattle.step');	
            this.markDirty('champsbattle.teamSaved');	
            this.markDirty('champsbattle.score');	
        }

        return champsbattle;
    },

    saveChampsBattleTeams: function(teams, userData) {
        var user = this.user;
        var champsbattle = this.getChampsBattle();
        if (champsbattle.teamSaved) {
            return false;
        }
        
        objectForEach(champsbattle.teams, function(id, team) {
            team.team = teams[id] || {};
            this.markDirty(util.format('champsbattle.teams.%d.team', id));
        }.bind(this));
        

        champsbattle.attrs = {};
        var attrs = champsbattle.attrs;
        var roleAttrs = userData.roleAttrs;
        objectForEach(roleAttrs, function(rid, attr) {
            attrs[rid] = {init_health:attr.health, health:attr.health}; 
        });

        champsbattle.teamSaved = true;
        this.markDirty('champsbattle.teamSaved');
        this.markDirty('champsbattle.attrs');

        user.role = userData.role;
        user.pet = userData.pet;
        user.roleAttrs = roleAttrs;
        this.markDirty('role');
        this.markDirty('pet');
        this.markDirty('roleAttrs');

        return true;
    },

    recoverChampsBattleTeam: function(teamId, recover) {
        var champsbattle = this.getChampsBattle();
        var attrs = champsbattle.attrs;
        var team = champsbattle.teams[teamId];
        if (!team) {
            return;
        }

        objectForEach(team.team, function(pos, rid) {
        	var attr = attrs[rid];
            if (attr.health < attr.init_health) {
                attr.health = Math.min(attr.init_health, attr.health + Math.floor(attr.init_health*recover));
            }
        });
        this.markDirty('champsbattle.attrs');
    },
}

function PlayerManager() {
    var _players = {};

    var _create = function(user) {
        var player = new Player(user);
        _players[player.uid] = player;
        return player;
    }

    this.init = function(callback) {
        var cursor = gDBUser.find();
        cursor.each(function(err, item) {
            if (err) {
                callback(err);
                return;
            }

            if (cursor.isClosed()) {
                callback();
                return;
            }
            
            _create(item);
        });
    };

    this.get = function(uid) {
        return _players[uid];
    };

    this.players = function() {
        return _players;
    };

    this.load = function(user, callback) {
        var player = _players[user._id];
        if (!player) {
            player = _create(user);
            gDBUser.insert(player.user, function(err, result){
                player.loaded = true;
                callback && callback(player);
            });
        } else {
            if (user.info) {
                player.user.info = user.info;
            }

            if (user.status) {
                player.user.status = user.status;
            }
            
            player.loaded = true;
            callback && callback(player);
        }
    };

    this.save = function(force, callback) {
        var uids = Object.keys(_players);
        var loader = new common.Loader(callback);

        uids.forEach(function(uid) {
            loader.addLoad(uid);
        });

        uids.forEach(function(uid) {
            var player = _players[uid];
            player.save(force, function() {
                loader.onLoad(uid); 
            });
        });

        loader.done();
    };

    this.each = function(callback) {
        for (var uid in _players) {
            callback(_players[uid]);
        }
    };
}

exports.Player = Player;
exports.gPlayers = new PlayerManager();
